package com.zx._03_并发.chapter_06_compent;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StopWatch;

/**
 * 同步组件——ReentrantLock
 */
@Slf4j
public class Demo_04_ReentrantLock {

    // 创建一个锁，默认是非公平锁
    private final static ReentrantLock lock = new ReentrantLock();
    // 请求总数
    public static int clientTotal = 5000;
    // 同时并发执行的线程数
    public static int threadTotal = 200;
    public static int count = 0;
    // 创建一个公平锁
    //private final static ReentrantLock lock = new ReentrantLock(true);

    public static void main(String[] args) throws Exception {
        StopWatch sw = new StopWatch();
        ExecutorService executorService = Executors.newCachedThreadPool();
        final CountDownLatch countDownLatch = new CountDownLatch(clientTotal);
        sw.start("");
        for (int i = 0; i < clientTotal; i++) {
            final int index = i;
            executorService.execute(() -> {
                try {
                    add();
                    log.info("{}", index);
                } catch (Exception e) {
                }
                countDownLatch.countDown();
            });
        }
        countDownLatch.await();
        executorService.shutdown();
        sw.stop();
        log.info("count:【{}】,{}", count, sw.prettyPrint());
    }

    private static void add() throws InterruptedException {
        // 方式一，普通使用
//    	lock.lock();//上锁
//        try {
//			count++;
//		} finally {
//			lock.unlock();//解锁
//		}
        // 方式二，尝试获得锁，如果当前锁没有被其他的线程占用的话，就上锁；否则方法不会阻塞
        // 这个方式很容易出现问题，造成线程不安全
//        if(lock.tryLock()) {
//        	try {
//    			count++;
//    		} finally {
//    			lock.unlock();//解锁
//    		}
//        }
        // 方式三，尝试获得锁，如果当前锁没有被其他的线程占用的话，就上锁；否则方法阻塞，等待一段时间
        // 这个方式相比方式二要靠谱很多
        if (lock.tryLock(100L, TimeUnit.MILLISECONDS)) {
            try {
                count++;
            } finally {
                lock.unlock();//解锁
            }
        }
    }
}
